#include <gtk/gtk.h>
#include <string.h>
#include <unistd.h>
#include "client.h"
#include "callbacks.h"

gchar* ui_file[] = {"ui/init.ui", "ui/main.ui", "ui/reg.ui", "ui/about.ui", "ui/chat.ui"};

GtkBuilder *get_builder (gint ui)
{	
	GtkBuilder *builder = gtk_builder_new ();
	GError* error = NULL;
	if (!gtk_builder_add_from_file (builder, ui_file[ui], &error))
	{
		g_warning ("Couldn't load builder file: %s", error->message);
		g_error_free (error);
	}
	gtk_builder_connect_signals (builder, NULL);

	return builder;
}

GtkBuilder *get_chat_builder (const gchar *user)
{
	int i;
	for (i = 0; i < USER_NUM_MAX; i++)
		if ( strcmp(chat_user[i], user) == 0)
			return chat_builders[i];

	GtkBuilder *chat_builder = get_builder(CHAT);

	for (i = 0; (i < USER_NUM_MAX) && (strlen(chat_user[i]) > 0); i++);

	memset(chat_user[i], 0, NAME_LEN_MAX + 1);
	strcpy(chat_user[i], user);

	chat_builders[i] = chat_builder;

	return chat_builder;
}

void reinit_chat_builder (const gchar *user)
{
	int i;
	for (i = 0; i < USER_NUM_MAX; i++)
		if ( strcmp(chat_user[i], user) == 0)
		{
			memset (chat_user[i], 0, NAME_LEN_MAX + 1);
			chat_builders[i] = NULL;
		}
}

/* Log In */
void on_button1_clicked (GtkWidget *widget, gpointer data)
{
	GtkWindow *window;
        window = GTK_WINDOW(gtk_builder_get_object (init_builder, "window"));

	GtkEntry *entry;
	entry = GTK_ENTRY (gtk_builder_get_object (init_builder, "name_entry"));
	const gchar *name = gtk_entry_get_text (entry);
	entry = GTK_ENTRY (gtk_builder_get_object (init_builder, "passwd_entry"));
	const gchar *passwd = gtk_entry_get_text (entry);
	
	if (sock_fd == -1)
	{
		if (net_init(server_ip) == -1)
		{
			const gchar *info = "Network not available.";
			GtkMessageDialog *dialog = gtk_message_dialog_new ( window,
					GTK_DIALOG_DESTROY_WITH_PARENT,
					GTK_MESSAGE_WARNING,
					GTK_BUTTONS_OK,
					info);
			gtk_dialog_run (GTK_DIALOG(dialog));
			gtk_widget_destroy (GTK_WIDGET(dialog));
			return ;
		}
	}

	if ( (strlen(name) == 0) || (strlen(passwd) == 0))
	{
		const gchar *info = "Name or password shouldn't be null.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( window,
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}


	int result = log_in(name, passwd);
	if (result == NAME_NOT_EXIST) 
	{
		const gchar *info = "User name not exist or password error.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( window,
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}
	else if (result == PASSWD_INCORRECT)
	{
		const gchar *info = "Password incorrect.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( window,
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}

	main_builder = get_builder(MAIN);
	gtk_widget_destroy (GTK_WIDGET(window));

	GtkTreeView *tv = GTK_TREE_VIEW (gtk_builder_get_object (main_builder, "treeview"));
	g_signal_connect(tv, "row-activated", (GCallback) on_main_treeview_double_clicked, NULL);

	GtkListStore *liststore = gtk_list_store_new(1, G_TYPE_STRING); 

	g_thread_create(user_ls_thread, liststore, FALSE, NULL);

	gtk_tree_view_set_model(GTK_TREE_VIEW(tv),GTK_TREE_MODEL(liststore)); 

	GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); 
	GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes ("User List:", renderer, "text", 0, NULL);

	gtk_tree_view_append_column (tv, column);  

	window = GTK_WIDGET (gtk_builder_get_object (main_builder, "window"));
	gtk_window_set_title (window, log_in_as);
	gtk_window_present (window);
	g_thread_create(listen_thread, NULL, FALSE, NULL);
}

void *user_ls_thread(void *arg)
{	
	while (1)
	{
		user_ls();
		gdk_threads_enter ();
		GtkListStore *liststore = GTK_LIST_STORE (arg);
		gtk_list_store_clear (liststore);
		int i;
		for (i = 0; i < USER_NUM_MAX; i++)
			if ( (strlen(users[i]) > 0) && (strcmp(users[i], log_in_as) != 0))
			{
				char name_tmp[NAME_LEN_MAX + 1];
				memset (name_tmp, 0, NAME_LEN_MAX + 1);
				if ( strcmp(users[i], "ALL") == 0)
					strcpy(name_tmp, users[i]);
				else if (user_online[i] == 1)
					sprintf(name_tmp, "on_line\t%s", users[i]);
				else
					sprintf(name_tmp, "offline\t%s", users[i]);
				GtkTreeIter iter; 
				gtk_list_store_append(liststore, &iter); 
				gtk_list_store_set (liststore, &iter, 0, name_tmp, -1);
			}
		gdk_flush ();
		gdk_threads_leave ();
		sleep (5);		
	}	
}

void *listen_thread(void *arg)
{
	int tmp;
	gchar from[NAME_LEN_MAX +1], msg[MSG_LEN_MAX +1];
	while (1)
	{
		recv(sock_fd2, &tmp, sizeof(int), 0);
		memset(from, 0, NAME_LEN_MAX + 1);
		recv(sock_fd2, from, tmp, 0);	

		recv(sock_fd2, &tmp, sizeof(int), 0);
		memset(msg, 0, MSG_LEN_MAX + 1);
		recv(sock_fd2, msg, tmp, 0);	

		gdk_threads_enter ();

		GtkBuilder *builder = get_chat_builder(from);
		GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "window"));
		gtk_window_set_title (window, from);
		gtk_window_present (window);

		char reflect[MSG_LEN_MAX + 1];
        	memset (reflect, 0, MSG_LEN_MAX + 1);
	        sprintf (reflect, "%s said:\n%s\n", from, msg);

		GtkTextIter end;
		GtkTextView *recv_tv = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "recv_textview"));
        	GtkTextBuffer *recv_buf = gtk_text_view_get_buffer (recv_tv);
	        gtk_text_buffer_get_end_iter (recv_buf, &end);
	        gtk_text_buffer_insert (recv_buf, &end, reflect, strlen(reflect));

		gdk_flush ();
		gdk_threads_leave ();
	}
}

/* Register */
void on_button2_clicked (GtkWidget *widget, gpointer data)
{
	reg_builder = get_builder(REGISTER);
	GtkDialog *window = GTK_DIALOG (gtk_builder_get_object (reg_builder, "dialog"));
	gtk_dialog_run(window);
}

/* About Us */
void on_button3_clicked (GtkWidget *widget, gpointer data)
{
	about_builder = get_builder(ABOUT);
	GtkDialog *window = GTK_DIALOG (gtk_builder_get_object (about_builder, "aboutdialog"));
	gtk_dialog_run(window);
	gtk_widget_destroy(GTK_WIDGET(window));
}

void on_reg_ok_button_clicked (GtkWidget *widget, gpointer data)
{
	GtkDialog *window;
	window = GTK_DIALOG (gtk_builder_get_object (reg_builder, "dialog"));

	if (sock_fd == -1)
	{
		if (net_init(server_ip) == -1)
		{
			const gchar *info = "Network not available.";
			GtkMessageDialog *dialog = gtk_message_dialog_new ( GTK_WINDOW (window),
					GTK_DIALOG_DESTROY_WITH_PARENT,
					GTK_MESSAGE_WARNING,
					GTK_BUTTONS_OK,
					info);
			gtk_dialog_run (GTK_DIALOG(dialog));
			gtk_widget_destroy (GTK_WIDGET(dialog));
			return ;
		}
	}

	GtkEntry *entry;
        entry = GTK_ENTRY (gtk_builder_get_object (reg_builder,  "name_entry"));
	const gchar *name = gtk_entry_get_text (entry);
	entry = GTK_ENTRY (gtk_builder_get_object (reg_builder,  "passwd_entry"));
	const gchar *passwd = gtk_entry_get_text (entry);
	entry = GTK_ENTRY (gtk_builder_get_object (reg_builder,  "passwd2_entry"));
	const gchar *passwd2 = gtk_entry_get_text (entry);

	if ( (strlen(name) == 0) || (strlen(passwd) == 0) || (strlen(passwd2) ==0 ) ) 
	{
		const gchar *info = "Name or password shouldn't be null.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( window,
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}

	if ( strcmp(passwd, passwd2) != 0)
	{
		const gchar *info = "Retype password error.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( GTK_WINDOW (window),
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}

	if ( reg(name, passwd) == -1)
	{
		const gchar *info = "Name already userd.";
		GtkMessageDialog *dialog = gtk_message_dialog_new ( GTK_WINDOW (window),
				GTK_DIALOG_DESTROY_WITH_PARENT,
				GTK_MESSAGE_WARNING,
				GTK_BUTTONS_OK,
				info);
		gtk_dialog_run (GTK_DIALOG(dialog));
		gtk_widget_destroy (GTK_WIDGET(dialog));
		return ;
	}

	const gchar *info = "Register success.";
	GtkMessageDialog *dialog = gtk_message_dialog_new ( GTK_WINDOW (window),
			GTK_DIALOG_DESTROY_WITH_PARENT,
			GTK_MESSAGE_WARNING,
			GTK_BUTTONS_OK,
			info);
	gtk_dialog_run (GTK_DIALOG(dialog));
	gtk_widget_destroy (GTK_WIDGET(dialog));

	gtk_widget_destroy(GTK_WIDGET(window));
}

void on_reg_cancel_button_clicked (GtkWidget *widget, gpointer data)
{
	GtkDialog *window = GTK_DIALOG (gtk_builder_get_object (reg_builder, "dialog"));
	gtk_widget_destroy(GTK_WIDGET(window));
}

void on_chat_send_msg_button_clicked (GtkWidget *widget, gpointer data)
{
	GtkWindow *window = GTK_WINDOW (widget);
	const gchar *name = gtk_window_get_title (window);
	GtkBuilder *builder = get_chat_builder(name);

	GtkTextView *send_tv = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "send_textview"));
	GtkTextBuffer *send_buf = gtk_text_view_get_buffer (send_tv);
	GtkTextIter start, end;
	gtk_text_buffer_get_start_iter (send_buf, &start);
	gtk_text_buffer_get_end_iter (send_buf, &end);
	gchar *msg = gtk_text_buffer_get_text (send_buf, &start, &end, FALSE);
	gtk_text_buffer_set_text (send_buf, "", 0);
	if ( strlen(msg) == 0)
		return ;

	int res;
	if ( strcmp(name, "ALL") == 0)
	{
		res = chat_to_all(log_in_as, msg);
	}
	else
	{
		res = chat_to(log_in_as, name, msg);
	}

	printf("client: %d\n", res);
	char reflect[MSG_LEN_MAX + 1];
	memset (reflect, 0, MSG_LEN_MAX + 1);
	sprintf (reflect, "%s said:\n%s\n", log_in_as, msg);

	if ( res != 0)
		strcat (reflect, "Send error.Please try again.\n");

	GtkTextView *recv_tv = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "recv_textview"));
	GtkTextBuffer *recv_buf = gtk_text_view_get_buffer (recv_tv);
	gtk_text_buffer_get_end_iter (recv_buf, &end);
	gtk_text_buffer_insert (recv_buf, &end, reflect, strlen(reflect));
}

void on_main_treeview_double_clicked (GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, gpointer p)
{
	GtkTreeModel *model = gtk_tree_view_get_model(tv);
	GtkTreeIter iter;
	if (gtk_tree_model_get_iter(model, &iter, path))
	{
		gchar *name_tmp;
	  	gtk_tree_model_get(model, &iter, 0, &name_tmp, -1);

		printf("tt%s\n", name_tmp);

		char name[NAME_LEN_MAX + 1];
		memset (name, 0, NAME_LEN_MAX + 1);

		if ( strcmp(name_tmp, "ALL") == 0)
			strcpy (name, name_tmp);
		else
			strcpy (name, strchr(name_tmp, (int)('\t')) + 1);

		GtkBuilder *builder = get_chat_builder(name);
		GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "window"));
		gtk_window_set_title (window, name);
		gtk_window_present (window);
	}
}

void on_main_window_destroy (GtkWidget *widget, gpointer data){
	log_out(log_in_as);
	gtk_main_quit();
}

void on_chat_window_destroy (GtkWidget *widget, gpointer data){
	GtkWindow *window = GTK_WINDOW (data);
	const gchar *name = gtk_window_get_title (window);
	reinit_chat_builder (name);
}

void on_window_destroy (GtkWidget *widget, gpointer data){
	if (main_builder == NULL)
		gtk_main_quit();
}
